﻿//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//    ReminderOutlookUtilsTest.cs
//
// Abstract:
//
//    Unit tests for ReminderOutlookUtils class
//
//--

using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Office.Interop.Outlook;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.EnhancedReminders.OutlookAddIn.UnitTests
{
    
    
    /// <summary>
    ///This is a test class for ReminderOutlookUtilsTest and is intended
    ///to contain all ReminderOutlookUtilsTest Unit Tests
    ///</summary>
    [TestClass()]
    [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
        Justification = "Class name reflect type name being tested")]
    public class ReminderOutlookUtilsTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        /// <summary>
        ///A test for TryParseRemindTime. Invalid string
        ///</summary>
        [TestMethod()]
        public void TryParseRemindTimeInvalidInputTest()
        {
            string text = "rubbish"; 
            int minutes = 0; 
            int minutesExpected = -1; 
            bool expected = false; 
            bool actual;
            actual = ReminderOutlookUtils_Accessor.TryParseRemindTime(text, out minutes);
            Assert.AreEqual(minutesExpected, minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for TryParseRemindTime. Invalid digit
        ///</summary>
        [TestMethod()]
        public void TryParseRemindTimeNegativeTest()
        {
            string text = "-1 hours";
            int minutes = 0;
            int minutesExpected = -1;
            bool expected = false;
            bool actual;
            actual = ReminderOutlookUtils_Accessor.TryParseRemindTime(text, out minutes);
            Assert.AreEqual(minutesExpected, minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for TryParseRemindTime. Valid input, invalid singularity
        ///</summary>
        [TestMethod()]
        public void TryParseRemindTimeValidMinuteTest()
        {
            string text = "5 minute";
            int minutes = 0;
            int minutesExpected = 5;
            bool expected = true;
            bool actual;
            actual = ReminderOutlookUtils_Accessor.TryParseRemindTime(text, out minutes);
            Assert.AreEqual(minutesExpected, minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for TryParseRemindTime. Valid input, invalid plurality
        ///</summary>
        [TestMethod()]
        public void TryParseRemindTimeValidMinutesTest()
        {
            string text = "1 minutes";
            int minutes = 0;
            int minutesExpected = 1;
            bool expected = true;
            bool actual;
            actual = ReminderOutlookUtils_Accessor.TryParseRemindTime(text, out minutes);
            Assert.AreEqual(minutesExpected, minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for TryParseRemindTime. Years is invalid.
        ///</summary>
        [TestMethod()]
        public void TryParseRemindTimeYearsTest()
        {
            string text = "5 years";
            int minutes = 0;
            int minutesExpected = -1;
            bool expected = false ;
            bool actual;
            actual = ReminderOutlookUtils_Accessor.TryParseRemindTime(text, out minutes);
            Assert.AreEqual(minutesExpected, minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for TryParseRemindTime. Ending string should be used.
        ///</summary>
        [TestMethod()]
        public void TryParseRemindTimeHoursFollowedByMinutesTest()
        {
            string text = "5 hour 3 minutes";
            int minutes = 0;
            int minutesExpected = 5;
            bool expected = true;
            bool actual;
            actual = ReminderOutlookUtils_Accessor.TryParseRemindTime(text, out minutes);
            Assert.AreEqual(minutesExpected, minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for TryParseRemindTime. Ending string should be used.
        ///</summary>
        [TestMethod()]
        public void TryParseRemindTimeMinutesFollowedByHoursTest()
        {
            string text = "30 minutes 5 hours";
            int minutes = 0;
            int minutesExpected = 1800;
            bool expected = true;
            bool actual;
            actual = ReminderOutlookUtils_Accessor.TryParseRemindTime(text, out minutes);
            Assert.AreEqual(minutesExpected, minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for TryParseRemindTime. Space terminates digits
        ///</summary>
        [TestMethod()]
        public void TryParseRemindTimeSpaceSeparatedTest()
        {
            string text = "5 3 hours";
            int minutes = 0;
            int minutesExpected = 300;
            bool expected = true;
            bool actual;
            actual = ReminderOutlookUtils_Accessor.TryParseRemindTime(text, out minutes);
            Assert.AreEqual(minutesExpected, minutes);
            Assert.AreEqual(expected, actual);
        }
        
        /// <summary>
        ///A test for FormatRemindTime. Format less than an hour's worth of minutes
        ///</summary>
        [TestMethod()]
        public void FormatRemindTimeMinuteTest()
        {
            int minutes = 1; 
            string expected = "1 minute"; 
            string actual;
            actual = ReminderOutlookUtils_Accessor.FormatRemindTime(minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for FormatRemindTime. Format "-1"
        ///</summary>
        [TestMethod()]
        public void FormatRemindTimeNegativeTest()
        {
            int minutes = -1;
            string expected = "None";
            string actual;
            actual = ReminderOutlookUtils_Accessor.FormatRemindTime(minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for FormatRemindTime. Format 1 hour + 1 minute
        ///</summary>
        [TestMethod()]
        public void FormatRemindTimeInexactHourTest()
        {
            int minutes = 61; 
            string expected = "61 minutes"; 
            string actual;
            actual = ReminderOutlookUtils_Accessor.FormatRemindTime(minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for FormatRemindTime. Format 1 hour worth of minutes
        ///</summary>
        [TestMethod()]
        public void FormatRemindTimeExactHourTest()
        {
            int minutes = 60; 
            string expected = "1 hour"; 
            string actual;
            actual = ReminderOutlookUtils_Accessor.FormatRemindTime(minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for FormatRemindTime. Format 1 day worth of minutes
        ///</summary>
        [TestMethod()]
        public void FormatRemindTimeSingularDayTest()
        {
            int minutes = 60 * 24; 
            string expected = "1 day"; 
            string actual;
            actual = ReminderOutlookUtils_Accessor.FormatRemindTime(minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for FormatRemindTime. Format 3 days worth of minutes
        ///</summary>
        [TestMethod()]
        public void FormatRemindTimePluralDayTest()
        {
            int minutes = 60 * 24 * 3;
            string expected = "3 days";
            string actual;
            actual = ReminderOutlookUtils_Accessor.FormatRemindTime(minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for FormatRemindTime. Test 1 day + 1 hour
        ///</summary>
        [TestMethod()]
        public void FormatRemindTimeInexactDayTest()
        {
            int minutes = 60 * 24 + 60;
            string expected = "25 hours";
            string actual;
            actual = ReminderOutlookUtils_Accessor.FormatRemindTime(minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for FormatRemindTime. Test singular week formatting
        ///</summary>
        [TestMethod()]
        public void FormatRemindTimeSingularWeekTest()
        {
            int minutes = 60 * 24 * 7;
            string expected = "1 week";
            string actual;
            actual = ReminderOutlookUtils_Accessor.FormatRemindTime(minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for FormatRemindTime. "60 * 24 * 7 * 2 minutes" should be formatted to 
        ///"2 weeks"
        ///</summary>
        [TestMethod()]
        public void FormatRemindTimePluralWeekTest()
        {
            int minutes = 60 * 24 * 7 * 2;
            string expected = "2 weeks";
            string actual;
            actual = ReminderOutlookUtils_Accessor.FormatRemindTime(minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for FormatRemindTime. "60 * 24 * 8 minutes" should be formatted to "8 days"
        ///instead of "1 week 1 day"
        ///</summary>
        [TestMethod()]
        public void FormatRemindTimeInexactWeekTest()
        {
            int minutes = 60 * 24 * 8;
            string expected = "8 days";
            string actual;
            actual = ReminderOutlookUtils_Accessor.FormatRemindTime(minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for FormatRemindTime. "720 minutes" should be formatted to "0.5 days"
        ///</summary>
        [TestMethod()]
        public void FormatRemindTimeHalfDayTest()
        {
            int minutes = 60 * 12;
            string expected = "0.5 days";
            string actual;
            actual = ReminderOutlookUtils_Accessor.FormatRemindTime(minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for FormatRemindTime. "1445 minutes" remains "1445 minutes"
        ///</summary>
        [TestMethod()]
        public void FormatRemindTimeRandomMinutesTest()
        {
            int minutes = 60 * 24 + 5;
            string expected = "1445 minutes";
            string actual;
            actual = ReminderOutlookUtils_Accessor.FormatRemindTime(minutes);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for ExtractTimeComponent "10minutes" should return "10"
        ///</summary>
        [TestMethod()]
        public void ExtractTimeComponentJoinedStringTest()
        {
            string text = "10minutes";
            int expected = 10;
            int actual;
            actual = ReminderOutlookUtils_Accessor.ExtractTimeComponent(text);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for ExtractTimeComponent. "1 5minutes" should return "1"
        ///</summary>
        [TestMethod()]
        public void ExtractTimeComponentWhiteSpaceSeparatedNumberTest()
        {
            string text = "1 5minutes";
            int expected = 1;
            int actual;
            actual = ReminderOutlookUtils_Accessor.ExtractTimeComponent(text);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for ExtractTimeComponent. "1minutes5hours" should return "1"
        ///</summary>
        [TestMethod()]
        public void ExtractTimeComponentCharSeparatedTest()
        {
            string text = "1minutes5hours";
            int expected = 1;
            int actual;
            actual = ReminderOutlookUtils_Accessor.ExtractTimeComponent(text);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        /// A test for overloaded LoadRules
        /// </summary>
        [TestMethod]
        public void LoadRulesWithRefRulesTest()
        {
            MockStorageItem storageItem = CreateMockStorageItemWithExistingData();

            MockApplication application = new MockApplication(storageItem);

            NotificationRules savedRules = new NotificationRules();
            savedRules.DoNotPromptUserOnDelete = true;
            savedRules.TimeZone = "Pacific Standard Time";
            ReminderOutlookUtils_Accessor.SaveRules(savedRules, application);

            NotificationRules rules = new NotificationRules();
            Assert.IsFalse(rules.DoNotPromptUserOnDelete, "rules.DoNotPromptUserOnDelete != true");
            ReminderOutlookUtils_Accessor.LoadRules(application, ref rules);
            Assert.IsTrue(rules.DoNotPromptUserOnDelete, "rules.DoNotPromptUserOnDelete == true");
        }

        /// <summary>
        /// A test for overloaded LoadChannels
        /// </summary>
        [TestMethod]
        public void LoadDefaultChannelsWithRefTest()
        {
            MockStorageItem storageItem = CreateMockStorageItemWithExistingData();
            MockApplication application = new MockApplication(storageItem);

            ObservableCollection<NotificationChannel> savedChannels = new ObservableCollection<NotificationChannel>();
            savedChannels.Add(new NotificationChannel(NotificationChannelType.Communicator));
            savedChannels.Add(new NotificationChannel(NotificationChannelType.Phone));

            ReminderOutlookUtils_Accessor.SaveChannels(savedChannels, application);

            List<NotificationChannel> newChannels = ReminderOutlookUtils_Accessor.LoadChannels(application, /*restoreDefaultsIfNecessary*/false);
            Assert.IsNotNull(newChannels, "Failed to load newChannels");
            Assert.IsTrue(newChannels.Count == 2, "Unexpected number of channels loaded");
        }

        /// <summary>
        /// A test for SaveRules
        /// </summary>
        [TestMethod]
        public void SaveRulesTest()
        {
            MockStorageItem storageItem = CreateMockStorageItemWithExistingData();
     
            MockApplication application = new MockApplication(storageItem);
            NotificationRules rules = new NotificationRules();
            ReminderOutlookUtils_Accessor.SaveRules(rules, application);

            rules = ReminderOutlookUtils_Accessor.LoadRules(application);
            Assert.IsNotNull(rules, "Original rules should be returned");
            Assert.IsTrue(rules.Count == 0, "Rules were created with no NotificationRuleItem");
        }

        /// <summary>
        /// A test for SaveChannels
        /// </summary>
        [TestMethod]
        public void SaveChannelsTest()
        {
            MockStorageItem storageItem = CreateMockStorageItemWithExistingData();
            MockApplication application = new MockApplication(storageItem);
            List<NotificationChannel> channels = new List<NotificationChannel>();
            channels.Add(new NotificationChannel());
            
            ReminderOutlookUtils_Accessor.SaveChannels(channels, application);

            channels = ReminderOutlookUtils_Accessor.LoadChannels(application, /*restoreDefaultsIfNecessary*/false);
            Assert.IsNotNull(channels, "Original channels should be returned");
            Assert.IsTrue(channels.Count == 1, "Channels were created with one NotificationChannel");
        }

        /// <summary>
        /// Helper method to create a mock storage item with an existing attachment.  This allows SaveRules()
        /// and SaveChannels() methods to be tested as these methods now re-load the existing data and then
        /// override the rules or channels portion before saving out.  By populating the attachment with a
        /// NotificationStorageData instance, loading the data succeeds.
        /// </summary>
        /// <returns></returns>
        private MockStorageItem CreateMockStorageItemWithExistingData()
        {
            MockStorageItem storageItem = new MockStorageItem(new MockAttachments(typeof(NotificationStorageData)));

            Collection<NotificationChannel> channels = new Collection<NotificationChannel>();
            channels.Add(new NotificationCustomChannel()); // Add a new channel (which will have a new GUID).

            // Add a rule with the cuurent timestamp to ensure it's unique.
            NotificationRules rules = new NotificationRules();
            rules.Add(new NotificationRuleItem(MailboxType.CalendarItem, "A random rule", System.DateTime.Now, null));

            NotificationStorageData storageData =
                new NotificationStorageData(new NotificationChannelList(channels), rules);

            OutlookUtils_Accessor.SaveAttachment(storageItem.Attachments, storageData);

            return storageItem;
        }
    }
}
